package infra

import (
	"bytes"
	"encoding/json"
	"fmt"
	openapi "github.com/alibabacloud-go/darabonba-openapi/client"
	sts20150401 "github.com/alibabacloud-go/sts-20150401/client"
	"github.com/alibabacloud-go/tea/tea"
	"net/url"
	"os"
	"strings"

	ossSdk "github.com/aliyun/aliyun-oss-go-sdk/oss"
)

type OssData struct {
	Region        string `json:"region"`
	AccessKey     string `json:"access_key"`
	AccessSecret  string `json:"access_secret"`
	SecurityToken string `json:"security_token"`
	Bucket        string `json:"bucket"`
	ExpireTime    int    `json:"expire_time"`
}

type IConfig interface {
	GetStsEndPoint() string
	GetEndPoint() string
	GetAccessKey() string
	GetAccessSecret() string
	GetBucket() string
	GetRegion() string
	GetRole() string
	GetExpire() int64
	GetOssUrl() string
	GetFrontUlr() string
}

// Config 配置
type Config struct {
	StsEndPoint  string // sts.cn-beijing.aliyuncs.com
	EndPoint     string // ali
	AccessKey    string
	AccessSecret string
	Bucket       string
	Region       string // oss-cn-beijing
	Role         string // acs:ram::1187757357704765:role/oss-user-role
	Expire       int64  // 过期时间
	OssUrl       string // 对象存储url
	FrontUrl     string // 前端url
}

func (c *Config) GetStsEndPoint() string  { return c.StsEndPoint }
func (c *Config) GetEndPoint() string     { return c.EndPoint }
func (c *Config) GetAccessKey() string    { return c.AccessKey }
func (c *Config) GetAccessSecret() string { return c.AccessSecret }
func (c *Config) GetBucket() string       { return c.Bucket }
func (c *Config) GetRegion() string       { return c.Region }
func (c *Config) GetRole() string         { return c.Role }
func (c *Config) GetExpire() int64        { return c.Expire }
func (c *Config) GetOssUrl() string       { return c.OssUrl }
func (c *Config) GetFrontUlr() string     { return c.FrontUrl }

type oss struct {
	conf IConfig
}

// Create 创建
func (o *oss) Create() (err error) {
	return
}

// Release 销毁
func (o *oss) Release() (err error) {
	return
}

func (o *oss) GetURL() string {
	return o.conf.GetFrontUlr()
}

func (o *oss) UploadBytes(objectKey string, dataByte []byte, ossCredentials OssData) error {
	// 创建OSS客户端
	ossClient, err := ossSdk.New(o.conf.GetEndPoint(), ossCredentials.AccessKey, ossCredentials.AccessSecret, ossSdk.SecurityToken(ossCredentials.SecurityToken))
	if err != nil {
		return err
	}

	bucket, err := ossClient.Bucket(o.conf.GetBucket())
	if err != nil {
		return err
	}

	return bucket.PutObject(objectKey, bytes.NewBuffer(dataByte))
}

// GetToken 获取Token
func (o *oss) GetToken() (oss OssData, err error) {
	var accessKeyID = o.conf.GetAccessKey()
	var accessKeySecret = o.conf.GetAccessSecret()
	fmt.Println(accessKeyID, accessKeySecret)
	client, err := o.createClient(&accessKeyID, &accessKeySecret)
	if err != nil {
		return
	}

	roleSessionName, roleArn := "OSS", o.conf.GetRole()
	var duration = o.conf.GetExpire()

	//var (
	//	policy = `{
	//      "Statement": [
	//          {
	//              "Action": "oss:*",
	//              "Effect": "Allow",
	//              "Resource": "*"
	//          }
	//      ],
	//      "Version": "1"
	//  }`
	//)
	assumeRoleRequest := &sts20150401.AssumeRoleRequest{
		DurationSeconds: &duration,
		//Policy:          &policy,
		RoleArn:         &roleArn,
		RoleSessionName: &roleSessionName,
	}
	resp, err := client.AssumeRole(assumeRoleRequest)
	if err != nil {
		return
	}

	type OSSInfo struct {
		Region          string  `json:"region"`
		AccessKeyId     string  `json:"accessKeyId"`
		AccessKeySecret string  `json:"accessKeySecret"`
		StsToken        *string `json:"stsToken"`
		Bucket          string  `json:"bucket"`
		ExpireTime      int     `json:"expireTime"`
	}

	var respInfo OSSInfo
	err = json.Unmarshal([]byte(resp.Body.Credentials.String()), &respInfo)
	if err != nil {
		return
	}

	oss.AccessKey = respInfo.AccessKeyId
	oss.AccessSecret = respInfo.AccessKeySecret
	oss.SecurityToken = *resp.Body.Credentials.SecurityToken
	oss.Region = o.conf.GetRegion()
	oss.Bucket = o.conf.GetBucket()
	oss.ExpireTime = int(duration)
	return
}

func (o *oss) PresignedPutObjectUrl(objectName string) (url *url.URL, bucket string, err error) {
	return
}

// createClient 创建Client
func (o *oss) createClient(accessKeyId *string, accessKeySecret *string) (*sts20150401.Client, error) {
	config := &openapi.Config{
		AccessKeyId:     accessKeyId,
		AccessKeySecret: accessKeySecret,
	}

	// 访问的域名
	config.Endpoint = tea.String(o.conf.GetStsEndPoint())
	result, err := sts20150401.NewClient(config)
	if err != nil {
		return nil, err
	}
	return result, nil
}

// GetObject 获取对象
func (o *oss) GetObject(objectName string) (url string, err error) {
	client, err := ossSdk.New(o.conf.GetEndPoint(), o.conf.GetAccessKey(), o.conf.GetAccessSecret())
	if err != nil {
		return "", err
	}

	// 获取存储空间
	bucket, err := client.Bucket(o.conf.GetBucket())
	if err != nil {
		return "", err
	}

	results := strings.Split(objectName, "/")
	url = fmt.Sprintf("./%s", results[len(results)-1])
	// 获取文件
	err = bucket.GetObjectToFile(objectName, url)
	if err != nil {
		return "", err
	}

	return url, nil
}

// DeleteObject 删除对象
func (o *oss) DeleteObject(url string) error {
	return os.Remove(url)
}

func NewOss(conf IConfig) *oss {
	return &oss{
		conf: conf,
	}
}

var Oss *oss

func init() {
	Oss = NewOss(&Config{
		StsEndPoint:  "sts.cn-shenzhen.aliyuncs.com",
		EndPoint:     "https://oss-cn-shenzhen.aliyuncs.com",
		AccessKey:    "LTAI5tGpmVvryKphPL9FMVKh",
		AccessSecret: "7Zz0LOWd8zKqHPUzMUDKALzGjiMpUX",
		Bucket:       "smartemc",
		//Region:       "oss-cn-shenzhen",
		Region:   "cn-shenzhen",
		Role:     "acs:ram::1102429080417818:role/aliyunstsrole",
		Expire:   900,
		FrontUrl: "",
	})
}
